(ns ura.handler
  (:require 
   [compojure.core :refer :all]
   [compojure.route :as route]
   [ring.middleware.json :refer [wrap-json-response wrap-json-body]]
   [ring.util.response :as rr :refer [response]]
   [ring.middleware.cors :refer [wrap-cors]]
   [ring.middleware.file :refer [wrap-file]]
   [ring.middleware.params :refer [wrap-params]]
   [ring.middleware.multipart-params :refer [wrap-multipart-params]]
   [ring.middleware.keyword-params :refer [wrap-keyword-params]]
   [ring.middleware.reload :refer [wrap-reload]]
   [taoensso.telemere :as t]
   [ura.data.AuthInfo :as ai]
   [ura.data.LogData :as ld]
   [ura.data.OrgInfo :as oi]
   [ura.data.RoleInfo :as ri]
   [ura.data.UserInfo :as ui]
   )
  )

;; define router
(defroutes router
  (GET  "/ura/test" req (do (t/log! req) (response {:resp "suce"})))
  (POST "/ura/test" request (do (t/log! (:body request)) (response {:resp "suce22"})))
  (GET "/err" {params :params :as req} (do
                                         (t/log! ["get test rquest: " params req])
                                         (throw (RuntimeException. "test error handle1"))
                                         ))

  (context "/ura/user" []
           (GET    "/"  {params :params} (response (ui/queryUserInfo params)))
           (GET    "/page"  {params :params} (response (ui/queryUserInfoPage params)))
           (GET    "/:id" [id] (response (ui/queryUserById (Integer/parseInt id))))
           (GET    "/orgList/:id"  [id] (response (ui/queryOrgList (Integer/parseInt id))))
           (GET    "/roleList/:id" [id] (response (ui/queryRoleList (Integer/parseInt id))))
           (GET    "/:name" [name] (response (ui/queryUserByName name)))
           (POST   "/" request (response {:result (ui/saveUser (:body request))}))
           (PUT    "/" request (response {:result (ui/updateUser (:body request))}))
           (DELETE "/:id" [id] (response {:result (ui/deleteUser id)}))
           (GET    "/:id/auth" [id] (response (ui/queryUserAuth (Integer/parseInt id))))
           (GET    "/:id/authMap" [id] (response (ui/query-user-auth-simple (Integer/parseInt id))))
           (POST   "/updatePassword" request (response (ui/updateUserPassword (:body request))))
           (POST   "/import" {params :params} (response (ui/importUserInfo params)) )
           )
  
  (context "/ura/org" []
           (GET "/" {params :params :as req} (response (oi/queryOrgInfo params)))
           (GET "/:id" [id] (response {:resp (oi/queryOrgById id)}))
           (PUT "/" request (response {:resp (oi/updateOrg (:body request))}))
           (POST "/" request (response {:resp (oi/saveOrg (:body request))} ))
           (DELETE "/:id" [id] (response {:resp (oi/deleteOrg id)}))
           )

  (context "/ura/role" []
           (GET "/" {params :params :as req} (response (ri/queryRoleInfo params)))
           (GET "/:id" [id] (response (ri/queryRoleById id)))
           (PUT "/" request (response {:resp (ri/updateRoleInfo (:body request))}))
           (POST "/" request (response {:resp (ri/saveRoleInfo (:body request))} ))
           (DELETE "/:id" [id] (response {:resp (ri/deleteRoleInfo id)}))
           )

  (context "/ura/auth" []
           (GET "/" {params :params :as req} (response (ai/queryAuthInfo params)))
           (GET "/:id" [id] (response (ai/queryAuthById id)))
           (PUT "/" request (response {:resp (ai/updateAuthInfo (:body request))}))
           (POST "/" request (response {:resp (ai/saveAuthInfo (:body request))} ))
           (DELETE "/:id" [id] (response {:resp (ai/deleteAuthInfo id)}))
           )
  
  (context "/ura/log" []
           (GET  "/" {params :params :as req} (response (ld/queryLog params)))
           (POST "/" request (response (str "response: " (ld/saveLog (:body request)))))
           (GET  "/modelList" [] (response (ld/getLogModels)))
           )

  (context "/ura/export" []
           (GET "/user" request (let [[file filename] (ui/exportData)
                                      resp     (-> (rr/file-response file)
                                                   (rr/header "Content-Disposition" (str "attachment;filename=" filename))
                                                   )
                                      ]
                                  (t/log! {:data resp} "get user export response")
                                  resp
                                  )
                )
           (GET "/log"  request (let [[file filename] (ld/exportLog)
                                      resp     (-> (rr/file-response file)
                                                   (rr/header "Content-Disposition" (str "attachment;filename=" filename))
                                                   )
                                      ]
                                  (t/log! {:data resp} "get log export response1")
                                  resp
                                  )
                )
           )
  (POST "/ura/login" request (response (ui/login (:body request))))
  (POST "/ura/logout" request (response (ui/logout (:body request))))

  (route/not-found "<h1>Page not found</h1>")
  )


(import
 java.time.format.DateTimeFormatter
 java.time.LocalDateTime
 )

;; 扩展cheshire, 支持LocalDateTime等的json化
(extend-protocol cheshire.generate/JSONable
  java.time.LocalDateTime
  (to-json [data gen]
    (cheshire.generate/write-string
     gen
     (.format (DateTimeFormatter/ofPattern "yyyy-MM-dd HH:mm:ss") data)
     )
    )
  )
;; (.format (java.time.format.DateTimeFormatter/ofPattern "yyyy-mm-dd") (java.time.LocalDateTime/now))

(defn logUrl   "记录url, middleware模板"
  [handler]
  (fn [req]
    (t/log! [(:uri req) (:request-method req)  (:params req) ])
    (t/log! :debug req)
    (handler req)
    )
  )

(defn wrap-exception "统一包装系统异常为 500 错误"
  [handler]
  (fn [request]
    (try
      (handler request)
      (catch Throwable e
        ;;(t/log!  [(.getLocalizedMessage e) e])
        (.printStackTrace e)
        {:status 500 :body (str "get exception: " (.getLocalizedMessage e))}
        ))
    )
  )

(def app
  (-> router
      wrap-reload
      logUrl
      wrap-exception
      wrap-json-response
      (wrap-json-body {:keywords? true :bigdecimals? false})
      wrap-keyword-params
      wrap-params
      wrap-multipart-params
      (wrap-file "./web/")
      (wrap-cors
                 :access-control-allow-origin [#".*"]
                 :access-control-allow-methods [:get :put :post :delete :options]
                 )
      ))
